﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Skugo.Shared;
using System.Windows;

namespace Skugo.StandardPlugins
{
    public class RemotePropertyNode
    {
        /// <summary>
        /// The type of the node (tells us how to interpret its data).
        /// </summary>
        public NodeKind Kind;

        /// <summary>
        /// The type that the node aims to represent, for example, a value type like Int32.
        /// </summary>
        public Type Type;

        /// <summary>
        /// Whether or not this node is by default expanded. Only applicable when the NodeKind is Expandable.
        /// </summary>
        public Boolean DefaultExpanded;

        /// <summary>
        /// The parent node (or null if this is the root node). The parent node is needed in cases where
        /// a value is set on the node, and the rpc system needs to send a property change (so it walks
        /// up the parents and gets each member id then sends it over).
        /// </summary>
        public RemotePropertyNode Parent;

        /// <summary>
        /// The name of the property if it has one, otherwise the property is considered an unnamed property.
        /// </summary>
        public String OptionalName;

        /// <summary>
        /// An optional description for the given object.
        /// </summary>
        public String OptionalDescription;

        /// <summary>
        /// The category that this property belongs to (optional, can be null).
        /// </summary>
        public String OptionalCategory;

        /// <summary>
        /// The array of all children that sit below this node.
        /// </summary>
        public RemotePropertyNode[] Children;

        /// <summary>
        /// The member index which this exists at. This is needed in cases where a property is changed on the
        /// node itself, and rpc needs that node's own member index to send the change to the other side.
        /// </summary>
        public UInt32 MemberIndex;

        /// <summary>
        /// The target that this node belongs to.
        /// </summary>
        public UInt32 TargetIndex;

        /// <summary>
        /// The current value of the node. The current value of the node is only used in cases where a
        /// the tree is being used as an external data source, such as a remote property grid.
        /// </summary>
        public Object CurrentValue;

        /// <summary>
        /// All the valid options for this node. Only valid if the if the node kind is an enumerable.
        /// </summary>
        public String[] EnumeratedOptions;

        /// <summary>
        /// The editor we use to display this property on the property grid.
        /// This is only used in the case of primitives.
        /// </summary>
        public ITypeEditor TypeEditor;

        /// <summary>
        /// In the case of a remote tree, the parameter types represent the types of a method's parameters.
        /// If this field is set, the type is assumed to be a method.
        /// </summary>
        public Type[] ParameterTypes;
    }


    public delegate void PropertyEditedFn(Object newValue);

    public interface ITypeEditor
    {
        /// <summary>
        /// Set the value of a type editor. Used when the property
        /// value changes externally, or is initially set.
        /// </summary>
        /// <param name="value">The new value of the property.</param>
        void SetValue(Object value);

        /// <summary>
        /// Is the type editor currently being used for editing?
        /// </summary>
        Boolean IsEditing { get; }

        /// <summary>
        /// If the type editor is considered large, it will be given its own line.
        /// Otherwise, the type editor is given the same line that the property name
        /// exists on.
        /// </summary>
        Boolean IsLarge { get; }

        /// <summary>
        /// Occurs when a property is changed by the type editor. The value returned
        /// is the new value of the property (which may need to be translated).
        /// </summary>
        event PropertyEditedFn OnPropertyEdited;

        /// <summary>
        /// The associated UI element (so we can attach the element to the property grid).
        /// </summary>
        FrameworkElement Content { get; }
    }
}
